#include "http_conn.h"
#define cout 0&&cout  // 禁用打印

// 定义HTTP响应的一些状态信息
const string ok_200_title = "OK";
const string error_400_title = "Bad Request";
const string error_400_form = "Your request has bad syntax or is inherently impossible to satisfy.";
const string error_403_title = "Forbidden";
const string error_403_form = "<html><body><div>You do not have permission to gry file from this server.Already have an account? Please <a href='/html/signin.html'>log in</a></div></body></html>";
const string error_404_title = "Not Found";
const string error_404_form = "<html><body>The requested file was not found on this server. <a href='/'>back home</a></body></html>";
const string error_500_title = "Internall error";
const string error_500_form = "There was an unusual problem serving the requested file.";

const string doc_root = "./resources"; // 网站的根目录


int http_conn::m_epollfd=-1;
int http_conn::m_user_count=0;
connection_pool* http_conn::m_p_conn_pool=nullptr;
shared_ptr<threadpool<http_conn>> http_conn::m_logic_thread_pool = nullptr;


// 设置文件描述符非阻塞
void setnonblocking(int fd){
    int flag = fcntl(fd, F_GETFL); // 获取flag
    flag |= O_NONBLOCK; // 新增设置：文件描述符非阻塞
    fcntl(fd, F_SETFL, flag);  // 设置flag
}

// 向epoll中添加需要监听的文件描述符
void addfd(int epollfd, int fd, bool one_short){
    cout << "向epoll:" << epollfd << " 中添加需要监听的文件描述符:" << fd << endl;
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLRDHUP; // 水平触发模式|客户端断开自动挂起
    // event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; 

    if(one_short){
        event.events |= EPOLLONESHOT; // 一个socket连接在任意时刻都只被一个线程处理
    }
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
    // 设置文件描述符非阻塞
    setnonblocking(fd);
}

// 从epoll中删除文件描述符
void removefd(int epollfd, int fd){
    cout << "从epoll:" << epollfd << " 中删除文件描述符:" << fd << endl;
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, 0);
    close(fd);
}

// 修改文件描述符
// 重置EPOLLONRSHOT事件，以确保下一次可读时，EPOLLIN事件能被触发
// 无法一次性读完时改为水平触发
void modfd(int epollfd, int fd, int ev, bool is_epollET){
    cout << "从epoll:" << epollfd << " 中修改文件描述符:" << fd << endl;
    epoll_event event;
    event.data.fd = fd;
    if(is_epollET)
        event.events = ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;  // 这里变成默认EPOLLONESHOT了............
    else
        event.events = ev | EPOLLONESHOT | EPOLLRDHUP; 
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}

// 初始化连接
void http_conn::init(int sockfd, const sockaddr_in& addr){
    cout << "init初始化连接" << endl;
    m_sockfd = sockfd;
    m_address = addr;
    m_user_name = "";
    m_user_id = "";

    // 设置端口复用
    int reuse = 1;
    setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

    // 添加到epoll对象中
    addfd(m_epollfd, m_sockfd, true);
    m_user_count++; // 总用户数+1
    
    state_init();
}

void http_conn::state_init(){
    cout << "state_init初始化当前参数状态" << endl;
    m_check_state = CHECK_STATE_REQUESTLINE; // 初始化主状态机状态为解析请求首行
    m_checked_index = 0;  // 当前正在分析的字符在读缓冲区的位置置0
    // m_start_line = 0; // 当前正在解析的行的起始位置置0
    m_read_idx = 0; // 读缓冲区中已经读入客户端数据的最后一个字节的下一个位置置0
    m_write_idx = 0;
    m_url = "";
    m_version = "";
    m_method = GET;
    m_host = "";
    m_linger = false;
    m_content_length = 0;
    m_content_text = "";
    m_content_type = "";
    is_readover = true;

    bzero(m_read_buf, READ_BUFFER_SIZE); // 将读缓冲的数据清空
    bzero(m_write_buf, WRITE_BUFFER_SIZE); 
    bzero(m_real_file, FILENAME_MAX); 
    cout << "state_init参数状态初始化完毕" << endl;
}

// 关闭连接
void http_conn::close_conn(){
    cout << "关闭连接" << endl;
    if(m_sockfd!=-1){
        removefd(m_epollfd, m_sockfd); // 从epoll中删除文件描述符m_sockfd
        m_sockfd=-1;
        m_user_count--; // 总用户数-1
    }
}

// 循环读取数据，直到无数据可读或对方关闭连接
bool http_conn::read(){
    cout << "read::循环读取数据" << endl;
    if(m_read_idx >= READ_BUFFER_SIZE){ // 当前读的位置超出读缓冲区的大小
        cout << "read::当前读的位置超出读缓冲区的大小" << endl;
        return false;
    }
    // 上次缓冲区的数据未读完，处理完毕后会把触发方式改为水平触发以便下次处理，现重新改回边缘触发方式
    if(!is_readover) modfd(m_epollfd, m_sockfd, EPOLLIN);
    is_readover = true;

    while (true)
    {
        cout << "read::循环一次" << endl;
        // 读到的字节
        int bytes_read = recv(m_sockfd, &m_read_buf[m_read_idx], READ_BUFFER_SIZE-m_read_idx,0);
        if(bytes_read == -1){
            if(errno == EAGAIN || errno == EWOULDBLOCK){ // 没有数据(上次触发时被一起读取了)，退出循环
                cout << "read::没有数据，退出循环" << endl;
                break;
            }
            cout << "read::出错" << endl;
            return false; // 出错
        }else if(bytes_read == 0){ // 对方关闭连接
            cout << "read::对方关闭连接" << endl;
            return false;
        }
        m_read_idx += bytes_read;
        if(m_read_idx==READ_BUFFER_SIZE){  // 读缓冲区已被填满
            cout << "read::读缓冲区已被填满" << endl;
            is_readover = false; // 标记缓冲区的数据未读完
            break;
        }
    }
    cout << "读取到了数据:" << m_read_buf << endl;
    return true;
}

// 写HTTP响应
bool http_conn::write(){
    cout << "write::写HTTP响应 " << "m_write_idx--" <<m_write_idx << endl;
    cout << "m_write_buf--" <<m_write_buf << endl;
    cout << "m_write_buf-len--" << strlen(m_write_buf) << endl;
    int temp = 0;
    long bytes_have_send = 0;
    // m_iv_count==2时，报头文件都要写
    long bytes_to_send = (m_iv_count==2?m_file_stat.st_size:0)+m_write_idx;
    cout << "write:: bytes_to_send--" <<bytes_to_send << endl;
    if(bytes_to_send==0){
        modfd(m_epollfd, m_sockfd, EPOLLIN);
        state_init();
        return true;
    }

    while(true){
        temp = writev(m_sockfd, m_iv, m_iv_count); // 分散写
        if(temp<=-1){
            // 如果TCP写缓冲区没有空间，则等待下一轮EPOLLOUT事件。虽然在此期间
            // 服务器无法立即接收到同一客户的下一个请求，但可以保证连接的完整性
            if(errno==EAGAIN){
                cout << "---------------------" << "TCP写缓冲区没有空间" << endl;
                modfd(m_epollfd, m_sockfd, EPOLLOUT);
                return true;
            }
            cout << "---------------------" << "分散写出错" << endl;
            unmap();
            return false;
        }

        // bytes_to_send -= temp;
        bytes_have_send += temp;
        cout << "bytes_to_send:" << bytes_to_send << "  bytes_have_send:" << bytes_have_send << endl;
        if(bytes_to_send<=bytes_have_send){
            // 发送HTTP响应成功，根据HTTP请求中的Connection字段决定是否立即关闭连接
            cout << "---------------------" << "发送HTTP响应成功" << endl;
            unmap();
            if(m_linger){
                state_init();
                modfd(m_epollfd, m_sockfd, EPOLLIN);
                cout << "保持连接" << endl;
                return true;
            }else{
                modfd(m_epollfd, m_sockfd, EPOLLIN);
                cout << "断开连接" << endl;
                return false;
            }
        }
    }
}

// 由IO线程池中的线程调用: 处理数据读写
void http_conn::process1(){
    cout << "process::由线程池工作线程调用,处理数据读写" << endl;

    if(is_need_read){ // 请求不完整
        if(read()){ // read成功，一次性把所有数据都读完
            m_logic_thread_pool->append(this);
        }else{  // read失败，关闭连接
            cout << "main: 读失败，关闭连接" << endl;
            this->close_conn();
        }
    }else{
        if(!write()){
            cout << "-----------main::写失败" << endl;
            this->close_conn();
        }
    }
}

// 由逻辑线程池中的线程调用: 处理HTTP请求的入口函数
void http_conn::process2(){
    cout << "process::由线程池工作线程调用,处理HTTP请求" << endl;
    // 解析HTTP请求
    HTTP_CODE read_ret = process_read();
    if(read_ret==NO_REQUEST){ // 请求不完整
        cout << "process::请求不完整" << endl;
        // 处理拆包
        m_read_idx -= m_checked_index; // 计算剩下的未处理的数据个数
        if(m_read_idx>0) strncpy(m_read_buf, m_read_buf+m_checked_index, m_read_idx); // 将未处理的数据放到m_read_buf数组的前端
        m_checked_index=0;
        if(!is_readover){ // 如果缓冲区数据未被读完，将触发方式改为水平触发以便继续读取
            cout << "process::缓冲区数据未被读完，将触发方式改为水平触发" << endl;
            modfd(m_epollfd, m_sockfd, EPOLLIN, false); 
        }
        return;
    }

    // 生成响应
    bool write_ret = process_write(read_ret);
    if(!write_ret){
        close_conn();
    }

    modfd(m_epollfd, m_sockfd, EPOLLOUT);
}

// 由线程池中的工作线程调用: 主状态机，解析请求
http_conn::HTTP_CODE http_conn::process_read(){
    cout << "process_read::解析HTTP请求" << endl;
    HTTP_CODE res = NO_REQUEST; // 报文解析状态置为没有服务器资源

    string text;

    // (m_check_state == CHECK_STATE_CONTENT && line_status == LINE_OK) || ((line_status = parse_line()) == LINE_OK)
    while((parse_line(text))==LINE_OK){ // 解析到了请求体并且请求体数据完整，或解析到一行完整的数据
        cout << "process_read::主状态机状态 " << m_check_state << endl;
        // text = get_line(); // 获取一行数据
        // m_start_line = m_checked_index; // 更新正在解析行的起始位置
        cout << "got 1 http line:" << text << endl;

        switch (m_check_state) // 主状态机状态
        {
            case CHECK_STATE_REQUESTLINE: // 正在分析请求行
                res = parse_request_line(text);
                if(res == BAD_REQUEST) // 客户请求若出现语法错误，直接结束
                    return BAD_REQUEST;
                break;
            case CHECK_STATE_HEADER: // 请求头
                res = parse_headers(stringstream(text));
                if(res == BAD_REQUEST)
                    return BAD_REQUEST;
                else if(res == GET_REQUEST) // 若获取了完整的客户请求，解析具体内容
                    return do_request();
                break;
            case CHECK_STATE_CONTENT: // 请求体
                res = parse_content();
                if(res == NO_REQUEST)
                    return NO_REQUEST;
                // else 
                if(res == GET_REQUEST) // 若获取了完整的客户请求，解析具体内容
                    return do_request();
                // line_stat = LINE_OPEN;  // 行读取状态设为行数据不完整
                break;
            default:
                return INTERNAL_ERROR; // 服务器内部错误
                break;
        }
    }
    return NO_REQUEST;
}
// 由线程池中的工作线程调用: 解析请求行，获取请求方法，目标URL，HTTP版本
http_conn::HTTP_CODE http_conn::parse_request_line(string& text){
    // GET / HTTP/1.1
    // auto idx = strpbrk(text.data(), " \t");
    cout << "parse_request_line::解析请求行 " << text << endl;
    auto iterSt = text.cbegin();
    smatch result;
    regex pattern("[^( |\t)]+");
    
    // GET
    if(!regex_search(iterSt, text.cend(), result, pattern))
        return BAD_REQUEST;
    cout << "parse_request_line::result[0]1 " << result[0] << endl;
    if(result[0].compare("GET")==0) m_method=GET;  // 只解析GET与POST方法
    else if(result[0].compare("POST")==0) m_method=POST;
    else return BAD_REQUEST; 
    iterSt = result[0].second;

    // /
    if(!regex_search(iterSt, text.cend(), result, pattern))
        return BAD_REQUEST;
    cout << "parse_request_line::result[0]2 " << result[0] << endl;
    string item(result[0]);
    if(string(item,0,7).compare("http://")==0){
        int idx = string(item).find('/', 7);    // 跳过前面的http://192.168.159.128:10000
        m_url.assign(item,idx,item.size()-idx);
    }else{
        m_url = item;
    }
    iterSt = result[0].second;
    
    // HTTP/1.1
    if(!regex_search(iterSt, text.cend(), result, pattern))
        return BAD_REQUEST;
    cout << "parse_request_line::m_version " << result[0] << endl;
    if(result[0].compare("HTTP/1.1")==0) m_version = result[0];
    else
        return BAD_REQUEST;  // 只解析HTTP1.1版本
    m_check_state = CHECK_STATE_HEADER; // 主状态机变成检查请求头
    cout << "parse_request_line::主状态机变成检查请求头 " << endl;
    return NO_REQUEST;
}

// 由线程池中的工作线程调用: 解析请求头部信息
http_conn::HTTP_CODE http_conn::parse_headers(stringstream ss){
    string item;
    getline(ss, item , ' '); 
    // cout << "parse_headers:: item "<< item << endl;
    // 遇到空行，表示头部解析完毕
    if(item.empty()){
        // 如果HTTP请求没有消息体，则已解析完整的HTTP请求
        if(m_content_length==0) return GET_REQUEST;
        // 否则主状态机转移到CHECK_STATE_CONTENT状态，还需要读取m_content_length字节的消息体
        m_check_state = CHECK_STATE_CONTENT;
        return NO_REQUEST;
    }

    if(item.compare("Connection:")==0){
        getline(ss, item); 
        if(item.compare("keep-alive")==0)
            m_linger = true;
    }else if(item.compare("Content-Length:")==0){
        getline(ss, item); 
        m_content_length = atol(item.data());
    }else if(item.compare("Host:")==0){
        getline(ss, m_host); 
        // cout << "parse_headers:: Host: "<< m_host << endl;
    }else if(item.compare("Content-Type:")==0){
        getline(ss, m_content_type, ';'); 
        cout << "parse_headers::m_content_type: " << m_content_type << endl;
        if(m_content_type.compare("multipart/form-data")==0){
            getline(ss, m_boundary, '='); // 跳过"boundary="
            getline(ss, m_boundary); // 给boundary赋值
            is_loadfile = false;
            // m_post_state = POST_ST;
            cout << "parse_headers::boundary: " << m_boundary << endl;
        }
    }else{
        cout << "opp! unknkow header " << item << endl;
    }
    return NO_REQUEST;
}

string http_conn::analyMultipartContent(string& text, int boundaryIdx1, int boundaryIdx2){
    int idxst = text.find("\n", boundaryIdx1)+1;
    idxst = text.find("\n", idxst)+1;
    idxst = text.find("\n", idxst)+1;
    int length = text.find("\n", idxst) - idxst -1;
    return string(text.begin()+idxst, text.begin()+boundaryIdx2-3);
}

// 由线程池中的工作线程调用: 解析请求体，密码、用户名、文件等信息，GET请求不存在请求体
http_conn::HTTP_CODE http_conn::parse_content(){
    cout << "parse_content::解析消息体----------" << endl;
    // 若是上传文件
    if(m_content_type.compare("multipart/form-data")==0){
        if(!is_loadfile){ // 如果不是正在下载文件，表明还未将信息插入数据库
            m_content_text = string(m_read_buf, m_checked_index, m_read_idx-m_checked_index); // 读取所有剩下的数据
            cout << "parse_content:读取所有剩下的数据" << m_content_text << endl;
            // 存在4个m_boundary时统一处理
            int idx0 = m_content_text.find(m_boundary);
            if(idx0==string::npos) return NO_REQUEST;
            int idx1 = m_content_text.find(m_boundary, idx0+1);
            if(idx1==string::npos) return NO_REQUEST;
            int idx2 = m_content_text.find(m_boundary, idx1+1);
            if(idx2==string::npos) return NO_REQUEST;
            int idx3 = m_content_text.find(m_boundary, idx2+1); 
            if(idx3==string::npos) return NO_REQUEST;
            cout << "parse_content:m_boundary: " << m_boundary <<endl;
            cout << "parse_content: idx0:" << idx0 << " idx1:" << idx1 << " idx2:" << idx2 << " idx3:" << idx3 << endl;

            // 解析
            string title(analyMultipartContent(m_content_text, idx0, idx1));
            cout << "parse_content:title--- " << title <<endl;
            string classid(analyMultipartContent(m_content_text, idx1, idx2));
            cout << "parse_content:classid--- " << classid <<endl;
            string posttext(analyMultipartContent(m_content_text, idx2, idx3));
            cout << "parse_content:posttext--- " << posttext <<endl;
            int idxst = m_content_text.find("filename=", idx3);
            if(idxst==string::npos) return NO_REQUEST;
            int idxed = m_content_text.find("\n", idxst);  // form-data; name="file"; filename="ceshi.m"\n
            if(idxed==string::npos) return NO_REQUEST;
            m_postfile = string(m_content_text.begin()+idxst+10, m_content_text.begin()+idxed-2);
            cout << "parse_content:m_postfile--- " << m_postfile <<endl;

            int idx = m_content_text.find("\n", idxed+1);   // Content-Type: application/octet-stream\n
            if(idx==string::npos) return NO_REQUEST;
            idx = m_content_text.find("\n", idx+1);  // \n
            if(idx==string::npos) return NO_REQUEST;
            m_checked_index += idx+1;
            
            //在post表中插入title，classid，posttext数据，浏览器端输入
            char query[4300];
            sprintf(query, "INSERT INTO post (postname,classid,posttext,postfile) VALUE ('%s','%s','%s','%s');", title.c_str(), classid.c_str(), posttext.c_str(), m_postfile.c_str());
            cout << "parse_content: query---" << string(query) << endl;
            // cout << "parse_content: query---" << string(query).size() << endl;
            // cout << "parse_content: query---" << strlen(query) << endl;
            if (get_sql_result(query, false, nullptr)==false)
            {
                cout << "parse_content:失败" << endl;
            }
            vector<vector<string>> res;
            sprintf(query, "SELECT max(postid) FROM post;"); // 查看刚插入记录的id
            if (get_sql_result(query, true, &res)==false)
            {
                return INTERNAL_ERROR;
            }
            m_postfile = res[0][0] + "/" + m_postfile;
            cout << "parse_content: new m_postfile---" << m_postfile << endl;
            is_loadfile = true; 
        }
        m_content_text = string(m_read_buf, m_checked_index, m_read_idx-m_checked_index); // 读取所有剩下的数据
        cout << "parse_content:文件的数据" << m_content_text << endl;
        int idx = m_content_text.find(m_boundary); // 文件内容结束标志
        if(idx==string::npos){
            m_content_length -= m_content_text.size();   // 更新剩下的请求体长度
            cout << "parse_content:剩下的请求体长度--- " << m_content_length <<endl;
            m_read_idx = 0;
            m_checked_index=0;
        }else{  // 文件内容获取完毕
            int idx2 = m_content_text.find("\n", idx);
            m_content_text = string(m_content_text, 0, idx-4); // 读取最后的文件数据

            // 解决粘包
            m_checked_index += idx2+1;
            cout << "parse_content:: 粘包数据 m_checked_index: " << m_checked_index << " m_read_idx: " << m_read_idx << endl;
            m_content_length = 0;
        }
        return GET_REQUEST;
    }
    // 非上传文件操作
    // 若读缓冲区已读入数据的尾后位置>=正在分析字符的起始位置+请求体长度,则读入m_content_length个数据赋给text
    else if(m_read_idx >= m_content_length + m_checked_index){
        m_content_text = string(m_read_buf, m_checked_index, m_content_length); // 请求体完整数据
        cout << "parse_content: 请求体数据: " << m_content_text << endl;
        
        // 处理粘包(如果有)
        m_read_idx -= m_content_length + m_checked_index; // 计算剩下的未处理的数据个数
        if(m_read_idx > 0) 
            strncpy(m_read_buf, m_read_buf+m_checked_index+m_content_length, m_read_idx); // 将未处理的数据放到读缓冲区起始位置
        m_checked_index=0;
        return GET_REQUEST;
    }
    return NO_REQUEST; // 消息体数据还未传输完整
}

// 由线程池中的工作线程调用: 从状态机。解析一行，非请求体判断依据/r/n
http_conn::LINE_STATUS http_conn::parse_line(string& text){
    // text = string(m_read_buf, m_checked_index, m_read_idx);
    // cout << "parse_line::被查找的字符串:"<< endl << text << endl;

    // 若当前正在解析请求体，直接返回
    if(m_check_state==CHECK_STATE_CONTENT){
        return LINE_OK;
    }

    int idx = string(m_read_buf).find("\r\n", m_checked_index); // 查找\r\n的位置
    cout << endl << "parse_line::解析一行 idx " << idx << "   m_checked_index " << m_checked_index << endl;
    if(idx == string::npos){ // 未找到\\r\\n的位置
        // cout << "parse_line::未找到\\r\\n的位置" << endl;
        return LINE_OPEN; // 未找到，数据尚不完整，被拆包了
    }
    text = string(m_read_buf, m_checked_index, idx-m_checked_index);
    m_checked_index = idx + 2; // 更新分析的字符位置为\r\n之后

    return LINE_OK;
}

// 由线程池中的工作线程调用: 得到一个完整、正确的HTTP请求时，我们就分析目标文件的属性
// 如果目标存在、对所有用户可读且不是目录，
// 则使用mmap将其映射到内存地址m_file_address处，并告诉调用者获取文件成功
http_conn::HTTP_CODE http_conn::do_request(){
    cout << "do_request::分析目标文件的属性 m_url:" << m_url << endl;

    if(m_url.find("/signin")!=string::npos){ // 请求登录
        cout << "do_request:: 请求登录" << endl;
        if(signin()) m_url="/";
    }else if(m_url.find("/register")!=string::npos){ // 请求注册
        cout << "do_request:: 请求注册" << endl;
        if(registered()) m_url="/html/signin.html";
    }else if(m_url.find("/upload")!=string::npos){ // 请求发帖子
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
        else if(save_file()) m_url="/";  // 此处由工作线程保存文件
        else return NO_REQUEST;         // 保存文件失败
    }else if(m_url.find("comment")!=string::npos){ // 请求发表评论
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
        if(!save_comment()) return NO_REQUEST;
    }else if(m_url.find("posting.html")!=string::npos){
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
    }

    if(m_url.compare("/")==0){ // 直接访问IP地址，如果还未登录进入登录页面，若已登录，访问首页面
        cout << "do_request:: 直接访问IP地址" << endl;
        if(m_user_id.empty())
            m_url="/html/signin.html";
        else
            return make_dir_html(CATEGORY); // 请求分类目录
    }else if(m_url.find("/classification/")!=string::npos){ // 请求分类中帖子目录
        cout << "/classification/" << endl;
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
        else
            return make_dir_html(POST_DIRECTORY);
    }else if(m_url.find("/post/")!=string::npos){ // 请求某个帖子
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
        else
            return make_dir_html(POST_CONTANT);
    }else if(m_url.find("/_src/")!=string::npos){ // 请求文件
        if(m_user_id.empty())
            return FORBIDDEN_REQUEST;
        else{   // 查找文件名，合成文件位置
            int idx = m_url.find("/_src/");
            string postid(m_url.begin()+idx+6, m_url.end());
            //在user表中检索username，passwd数据，浏览器端输入
            char query[1024];
            sprintf(query, "SELECT postfile FROM post WHERE postid='%s'", postid.c_str());
            vector<vector<string>> res;
            if (get_sql_result(query, true, &res)==false)
            {
                return NO_RESOURCE;
            }
            m_url.append("/"+res[0][0]);
            cout << "m_url:" << m_url << endl;
        }
    }
    
        // doc_root+m_url->m_real_file
    strcpy(m_real_file, doc_root.data());
    strncpy(m_real_file+strlen(m_real_file), m_url.data(), FILENAME_LEN-strlen(m_real_file)-1); 

    decode_str(m_real_file,m_real_file); // 解码

    if(stat(m_real_file,&m_file_stat)<0){ // 判断文件是否存在，结果存入m_file_stat
        cout << "do_request::文件 " << m_real_file << " 不存在" << endl;
        return NO_RESOURCE;
    }

    cout << "do_request::打开文件 " << m_real_file << endl;
    int fd = open(m_real_file, O_RDONLY);
    // mmap操作提供了一种机制，让用户程序直接访问设备内存，这种机制，相比较在用户空间和内核空间互相拷贝数据，效率更高
    m_file_address = (char*) mmap(0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
    return FILE_REQUEST;
    

    // if(!(m_file_stat.st_mode & S_IROTH)){
    //     return FORBIDDEN_REQUEST;
    // }
    // if(S_ISDIR(m_file_stat.st_mode)){ // 如果目标文件是目录
    //     cout << "do_request:目标文件是目录" << endl; 
    //     // 发送目录信息
    //     sprintf(m_dir_html, "<html><head><title>目录名:%s</title><head>", m_real_file);
    //     sprintf(m_dir_html+strlen(m_dir_html), "<body  style='background-color:rgb(10, 158, 133);'><hl>当前目录: %s</hl><table>", m_real_file);

    //     // 目录项二级指针 style="color:rgb(255, 255, 0) style="background-color:green;"
    //     struct dirent** ppdir;
    //     int num = scandir(m_real_file, &ppdir, nullptr, alphasort);
    //     char path[FILENAME_MAX] = {0};
    //     for(int i=0;i<num;++i){
    //         char* name = ppdir[i]->d_name;
    //         sprintf(path, "%s/%s", m_real_file, name);
    //         struct stat st;
    //         stat(path, &st);

    //         char enname[1024]={0};
    //         encode_str(enname,sizeof(enname),name);

    //         // 如果是文件 <td>%s</td>
    //         if(S_ISREG(st.st_mode)){
    //             sprintf(m_dir_html+strlen(m_dir_html), "<tr><td><a href=\"%s%s\">%s</a></td><td>%ld</td></tr>", 
    //                 m_url.data(), enname, name, (long)st.st_size);
    //         }
    //         // 如果是目录
    //         if(S_ISDIR(st.st_mode)){
    //             sprintf(m_dir_html+strlen(m_dir_html), "<tr><td><a href=\"%s%s/\">%s</a></td><td>%ld</td></tr>", 
    //                 m_url.data(), enname, name, (long)st.st_size);
    //         }
    //     }
    //     sprintf(m_dir_html+strlen(m_dir_html), "</table></body></html>");
    //     cout << "do_request: " << m_dir_html << endl; 
    // }
    //     return DIR_REQUEST;
}

bool http_conn::signin(){
    if(m_content_text.empty()) return false;
    int splitIdx = m_content_text.find("&");
    if(splitIdx==string::npos)
        return false;
    string username(m_content_text.begin()+5, m_content_text.begin()+splitIdx);
    string passwd(m_content_text.begin()+splitIdx+10,m_content_text.end());
    
    //在user表中检索username，passwd数据，浏览器端输入
    char query[1024];
    sprintf(query, "SELECT userid FROM user WHERE username='%s' AND passwd='%s'", username.c_str(), passwd.c_str());
    cout << "do_request: query---" << query << endl;
    vector<vector<string>> res;
    if (get_sql_result(query, true, &res)==false)
    {
        return false;
    }
    //结果为空,表明不存在该用户,进入登录错误页面
    if(res.empty()){
        m_url = "/html/signinError.html";
        return false;
    }
    //结果不为空,表明存在该用户,进入页面首页
    cout << "do_request: query---finduser" << endl;
    m_user_name = username;
    m_user_id = res[0][0];
    cout << "signin-m_user_name:" << m_user_name << "m_user_id:" << m_user_id << endl;
    return true;
}

bool http_conn::registered(){
    if(m_content_text.empty()) return false;
    int splitIdx1 = m_content_text.find("&");
    // cout << "splitIdx1" << splitIdx1 << endl;
    if(splitIdx1==string::npos){
        m_url = "/html/registerErrorPasswdDiff.html";
        return false;
    }
    int splitIdx2 = m_content_text.find("&",splitIdx1+1);
    // cout << "splitIdx2:" << splitIdx2 << endl;
    if(splitIdx2==string::npos){
        m_url = "/html/registerErrorPasswdDiff.html";
        return false;
    }

    string username(m_content_text.begin()+5, m_content_text.begin()+splitIdx1);
    string passwd(m_content_text.begin()+splitIdx1+10,m_content_text.begin()+splitIdx2);
    string enpasswd(m_content_text.begin()+splitIdx2+12,m_content_text.end());

    if(enpasswd.compare(passwd)!=0){
        m_url = "/html/registerErrorPasswdDiff.html";
        return false;
    }
    
    //在user表中插入username，passwd数据，浏览器端输入
    char query[1024];
    sprintf(query, "INSERT INTO user (username, passwd) VALUE ('%s','%s')", username.c_str(), passwd.c_str());
    
    if (get_sql_result(query, false)==false)
    {
        m_url = "/html/registerErrorUserExist.html";
        return false;
    }

    return true;
}

http_conn::HTTP_CODE http_conn::make_dir_html(SQL_CONTTANT conntant){
    sprintf(m_real_file, "/madeHTML.html");
    char query[256];
    vector<vector<string>> res;
    cout << "make_dir_html-------------------"<< endl;
    switch (conntant)
    {
    case CATEGORY: // 显示分类
        sprintf(query, "SELECT classname,classid FROM classification ORDER BY classid");
        if (get_sql_result(query, true, &res)==false)
        {
            return BAD_REQUEST;
        }
        // 发送目录信息
        sprintf(m_dir_html, "<html><body style='background-color:rgb(10, 158, 133);'><a href='/html/posting.html'><input type='button' value='发帖'/></a><h1>类别目录: </h1><table>");
        for(int i=0;i<res.size();++i){
            string classname=res[i][0];
            string classid = res[i][1];
            sprintf(m_dir_html+strlen(m_dir_html), "<br/><a href=\"/classification/%s\">%s</a><br/>", 
                classid.c_str(), classname.c_str());
        }       
        sprintf(m_dir_html+strlen(m_dir_html), "</table></body></html>");
        return DIR_REQUEST;
        break;
    case POST_DIRECTORY:{  // 显示分类中所有帖子
        cout << "POST_DIRECTORY:m_url--" << m_url << endl;
        int splitIdx = m_url.rfind("/");
        // cout << "POST_DIRECTORY:splitIdx--" << splitIdx << endl;
        string classid(m_url.begin()+splitIdx+1, m_url.end());
        // char* dot = strrchr(move(), '/');
        cout << "classid:" << classid << endl;


        // 查找类名
        sprintf(query, "SELECT classname FROM classification WHERE classid='%s'", classid.c_str());
        if (get_sql_result(query, true, &res)==false)
        {
            return BAD_REQUEST;
        }
        cout << "classname:" << res[0][0] << endl;
        // 发送目录信息
        sprintf(m_dir_html, "<html><body style='background-color:rgb(10, 158, 133);'><a href='/html/posting.html'><input type='button' value='发帖' /></a><h1>%s: </h1><table>", res[0][0].c_str());


        // 查找该类的帖子
        sprintf(query, "SELECT postname,postid FROM post WHERE classid='%s' ORDER BY postid", classid.c_str());
        if (get_sql_result(query, true, &res)==false)
        {
            return BAD_REQUEST;
        }
        
        for(int i=0;i<res.size();++i){
            string postname=res[i][0];
            string postid = res[i][1];
            cout << "POST_DIRECTORY：res[i][0]:" << res[i][0] << " res[i][1]:" << res[i][1] << endl;
            sprintf(m_dir_html+strlen(m_dir_html), "<br/><a href='/post/%s'>%s</a><br/>", 
                postid.c_str(), postname.c_str());
        }
        sprintf(m_dir_html+strlen(m_dir_html), "</table></body></html>");
        cout << "POST_DIRECTORY：" << m_dir_html << endl;
        return DIR_REQUEST;
        break;
    }
    case POST_CONTANT:{  // 显示帖子内容与评论
        cout << "POST_DIRECTORY:m_url--" << m_url << endl;
        int splitIdx = m_url.rfind("/");
        // cout << "POST_DIRECTORY:splitIdx--" << splitIdx << endl;
        string postid(m_url.begin()+splitIdx+1, m_url.end());
        
        // 查找帖子内容
        sprintf(query, "SELECT postname,posttext,postfile FROM post WHERE postid='%s' ", postid.c_str());
        
        if (get_sql_result(query, true, &res)==false)
        {
            return BAD_REQUEST;
        }

        // 发送帖子信息
        // 帖子标题
        sprintf(m_dir_html, "<html><body style='background-color:#FFA500;'><a href='/'><input type='button' value='首页' /></a><h1>%s: </h1><table>", res[0][0].c_str());
        // 帖子内容
        // sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:rgb(10, 120, 133); height:500px; width:100%' > %s </div>", res[0][1].c_str());
        sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:#DDDDDD;' > %s </div>", res[0][1].c_str());
        // 帖子文件连接
        sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:#EED7EE;'><a href='/_src/%s' download='%s'>%s</a></div>", postid.c_str(), res[0][2].c_str(), res[0][2].c_str());
        // 评论发表区
        sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:#DDDDDD;'><form action='/comment/%s' method='post'><textarea type='text' name='commtext' style='width:100%%; height:200px;font-size:18px' ></textarea><p/><input type='submit' value='发表'/></form></div>", postid.c_str());
        

        // 查找评论 按照时间逆序排序
        sprintf(query, "SELECT username, commtext FROM comment JOIN user USING(userid) WHERE postid='%s' ORDER BY create_data DESC", postid.c_str());
        if (get_sql_result(query, true, &res)==false)
        {
            return BAD_REQUEST;
        }
        
        // 评论
        for(int i=0; i<res.size(); ++i){
            sprintf(m_dir_html+strlen(m_dir_html), "<p/>");
            sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:FFD700; width:10%%; float:left;'>%s</div>", res[i][0].c_str()); // 评论者昵称
            sprintf(m_dir_html+strlen(m_dir_html), "<div style='background-color:DDDDDD; width:90%%; float:left;'>%s</div>", res[i][1].c_str()); // 评论内容
        }
        
        sprintf(m_dir_html+strlen(m_dir_html), " </table></body></html>");

        return DIR_REQUEST;
        break;
    }
    default:
        return INTERNAL_ERROR;
        break;
    }
    // string slash(strrchr(m_url.c_str(), '/'));
    // slash.erase(slash.begin());
    return INTERNAL_ERROR;
}

bool http_conn::get_sql_result(const char* query, bool is_query, vector<vector<string>>* result){
    cout << "get_sql_result: query--- "<< query << endl;
    //先从连接池中取一个连接
    MYSQL *mysql = NULL;
    connectionRAII mysqlcon(&mysql, m_p_conn_pool);

    // cout << "get_sql_result:查询语句---" << query;
    //在user表中检索username，passwd数据，浏览器端输入
    if (mysql_query(mysql, query))
    {
        cout << "error:" << mysql_error(mysql) << endl;
        return false;
    }
    if(!is_query) return true; //如果不是查询操作，直接返回
    //从表中检索完整的结果集
    MYSQL_RES *res = mysql_store_result(mysql);
    // cout << "MySQL 结果已返回" << endl;

    //返回结果集中的行数
    int num_rows = mysql_num_rows(res);
    cout << num_rows << endl;
    //返回结果集中的列数
    int num_fields = mysql_num_fields(res);
    cout << num_fields << endl;
    // result->resize(num_rows, vector<string>(num_fields));

    //返回所有字段结构的数组
    // MYSQL_FIELD *fields = mysql_fetch_fields(res);

    //从结果集中获取每一行数据
    int i=0;
    result->resize(num_rows);
    while (MYSQL_ROW row = mysql_fetch_row(res))
    {
        (*result)[i].resize(num_fields);
        cout << result->size() << " " << (*result)[0].size() << endl;
        for(int j=0;j<num_fields;++j){
            cout << "row[" << i << "][" << j << "]:" << row[j] << "   " << typeid(row[j]).name() << endl;
            (*result)[i][j]=row[j];
        }
        cout << "row[" << i << "] " << endl;
        ++i;
    }
    cout << "mysql查询完毕"<< endl;
    return true;
}

// 对内存映射区执行munmap操作
void http_conn::unmap(){
    cout << "unmap::解除内存映射" << endl;
    if(m_file_address){
        if(m_file_address){
            munmap(m_file_address, m_file_stat.st_size);
            m_file_address = 0;
        }
    }
}

bool http_conn::add_status_line(int status, const string& title)
{
    return add_response("%s %d %s\r\n", "HTTP/1.1", status, title.c_str());
}
bool http_conn::add_headers(int content_len)
{
    return add_content_length(content_len) && add_linger() &&
           add_content_type()&&add_blank_line();
}
bool http_conn::add_content_length(int content_len)
{
    return add_response("Content-Length:%d\r\n", content_len);
}
bool http_conn::add_content_type()
{
    cout << "add_content_type:" << m_real_file << endl;
    // 自右向左查找'.'字符，如不存在返回null
    char* dot = strrchr(m_real_file, '.');
    if(dot!=nullptr){
        cout << "add_content_type:" << dot << endl;
        if(strcmp(dot,".html")==0){
            cout << "add_content_type:" << dot << endl;
            return add_response("Content-Type:%s\r\n", "text/html;charset=utf-8");
        }
        if(strcmp(dot,".css")==0)  return add_response("Content-Type:%s\r\n", "text/css;charset=utf-8");
    }
    // 根据文件格式的不同而变化，如.mp3 .avi
    return add_response("Content-Type:%s\r\n", "text/plain;charset=utf-8");
}
bool http_conn::add_linger()
{
    return add_response("Connection:%s\r\n", (m_linger == true) ? "keep-alive" : "close");
}
bool http_conn::add_blank_line()
{
    return add_response("%s", "\r\n");
}
bool http_conn::add_content(const string& content)
{
    return add_response("%s", content.c_str());
}


// 往写缓冲区写入待发送的数据
bool http_conn::add_response(const char *format, ...)
{
    cout << "add_response::往写缓冲区写入待发送的数据" << endl; 
    cout << "add_response::m_write_idx--" << m_write_idx << endl; 
    if (m_write_idx >= WRITE_BUFFER_SIZE)
        return false;
    va_list arg_list;
    va_start(arg_list, format);
    int len = vsnprintf(m_write_buf + m_write_idx, 
            WRITE_BUFFER_SIZE - 1 - m_write_idx, format, arg_list);
    if (len >= (WRITE_BUFFER_SIZE - 1 - m_write_idx))
    {
        return false;
    }
    m_write_idx += len;
    cout << "add_response::m_write_idx--" << m_write_idx << " len--" <<len <<" m_write_buf--" << strlen(m_write_buf)<< endl; 
    va_end(arg_list);

    // LOG_INFO("request:%s", m_write_buf); ///////,,.............................................

    return true;
}

// 由线程池中的工作线程调用: 根据服务器处理HTTP请求的结果，决定返回给客户端的内容
bool http_conn::process_write(HTTP_CODE ret)
{
    cout << "process_write::根据HTTP请求,生成响应" << endl; 
    switch (ret)
    {
    case INTERNAL_ERROR:
    {
        add_status_line(500, error_500_title);
        add_headers(error_500_form.size());
        if (!add_content(error_500_form)){
            cout << "process_write::add_content false--" << endl;
            return false;
        }
        break;
    }
    case BAD_REQUEST:
    {
        add_status_line(400, error_400_title);
        add_headers(error_400_form.size());
        if (!add_content(error_400_form)){
            cout << "process_write::add_content false--" << endl;
            return false;
        }
        break;
    }
    case NO_RESOURCE:{
        sprintf(m_real_file, "/madeHTML.html");
        add_status_line(404, error_404_title);
        add_headers(error_404_form.size());
        if (!add_content(error_404_form)){
            cout << "process_write::add_content false--" << endl;
            return false;
        }
        break;
    }
    case FORBIDDEN_REQUEST:
    {
        sprintf(m_real_file, "/madeHTML.html");
        add_status_line(403, error_403_title);
        // add_headers(error_403_form.size());
        // if (!add_content(error_403_form)){
        // add_status_line(200, ok_200_title);
        add_headers(error_403_form.size());
        if (!add_content(error_403_form)){
            cout << "process_write::add_content false--" << endl;
            return false;
        }
        break;
    }
    case FILE_REQUEST:
    {
        add_status_line(200, ok_200_title);
        if (m_file_stat.st_size != 0)
        {
            add_headers(m_file_stat.st_size);
            m_iv[0].iov_base = m_write_buf;
            m_iv[0].iov_len = m_write_idx;
            m_iv[1].iov_base = m_file_address;
            m_iv[1].iov_len = m_file_stat.st_size;
            m_iv_count = 2;
            return true;
        }
        else
        {
            string ok_string = "<html><body></body></html>";
            add_headers(ok_string.size());
            if (!add_content(ok_string)){
                cout << "process_write::add_content false--" << endl;
                return false;
            }
        }

        break;
    }
    case UPLOAD_REQUEST:
        if(!is_readover) // 如果缓冲区数据未被读完，将触发方式改为水平触发以便继续读取
            modfd(m_epollfd, m_sockfd, EPOLLIN, false); 
        return true;
    case DIR_REQUEST:
    {
        cout << "DIR_REQUEST" << m_dir_html;
        add_status_line(200, ok_200_title);
        add_headers(strlen(m_dir_html));
        if (!add_content(m_dir_html)){
            cout << "process_write::add_content false--" << endl;
            return false;
        }
            
        break;
    }
    default:
        cout << "process_write::未定义的状态" << endl;
        return false;
    }
    m_iv[0].iov_base = m_write_buf;
    m_iv[0].iov_len = m_write_idx;
    m_iv_count = 1;
    return true;
}

bool http_conn::save_file(){
    // static fstream f;
    // static bool is_created = false;
    // if(!is_created){
    //     string filename = doc_root+"/_src/"+m_postfile;
    //     cout << "打开文件" << filename << endl;
	//     //二进制形式追加写入
	//     f.open(filename.c_str(), ios::out|ios::app| ios::binary);
    //     is_created = true;
    // }
    // cout << "save_file: " << m_content_text << endl;
    // f << m_content_text ;
    // if(m_content_length==0){ // 请求体中的数据都读完
    //     cout << "文件下载完毕" << endl;
    //     f.close();
    //     is_created = false;
    //     return true;
    // }

    static FILE* fp = nullptr;

    if(fp==nullptr){
        string filename = doc_root+"/_src/"+m_postfile;
        int idx = filename.rfind('/');
        mkdir(string(filename.begin(),filename.begin()+idx).c_str(), S_IRWXU);
        // #include <direct.h>
        cout << "打开文件" << filename << endl;
        fp = fopen(filename.c_str(), "w"); // 追加方式写二进制文件
    }
    cout << "save_file: " << m_content_text << endl;
    // fwrite(m_content_text.c_str(), sizeof(m_content_text), 1, fp);
    fwrite(m_content_text.c_str(), 1, m_content_text.size(), fp);
    if(m_content_length==0){ // 请求体中的数据都读完
        cout << "文件上传完毕" << endl;
        fclose(fp);
        fp=nullptr;
        return true;
    }

    cout << "save_file: 已写入" << endl;
    return false;
}

int http_conn::hexit(char c){
    if(c>='0'&&c<='9')
        return c-'0';
    if(c>='a'&&c<='f')
        return c-'a'+10;
    if(c>='A'&&c<='F')
        return c-'A'+10;
    return -1;
}
void http_conn::encode_str(char* to, int tosize, const char* from){
    int tolen;
    for(tolen=0;*from!=0&&tolen+4<tosize;++from){
        if(isalnum(*from)||strchr("/_.-~", *from)!=(char*)0){
            *to=*from;
            ++to;
            ++tolen;
        }else{
            sprintf(to, "%%%02x", (int)*from&0xff);
            to+=3;
            tolen+=3;
        }
    }
    *to = '\0';
}
// "编码"，用作回写浏览器的时候，将除字母数字及/_.-~以外的字符转义后写回
void http_conn::decode_str(char* to, const char* from){
    for(;*from!='\0';++to, ++from){
        if(from[0]=='%'&&isxdigit(from[1])&&isxdigit(from[2])){
            *to = hexit(from[1])*16+hexit(from[2]);
            from+=2;
        }else{
            *to=*from;
        }
    }
    *to = '\0';
}

bool http_conn::save_comment(){
    // cout << "save_comment" << endl;
    if(m_content_text.empty()) return false;

    int postIdx = m_url.rfind("/");
    if(postIdx==string::npos){
        return false;
    }
    string postid = string(m_url.begin()+postIdx+1, m_url.end());

    int commtextIdx = m_content_text.find("=");
    // cout << "splitIdx1" << splitIdx1 << endl;
    if(commtextIdx==string::npos){
        m_url = "/html/registerErrorPasswdDiff.html";
        return false;
    }
    string commtext(m_content_text.begin()+commtextIdx+1, m_content_text.end());
    
    char comm[commtext.size()+1];
    decode_str(comm, commtext.c_str()); // 解码

    //在comment表中插入userid,postid,commtext数据，浏览器端输入
    char query[1024];
    sprintf(query, "INSERT INTO comment (userid, postid, commtext) VALUE ('%s','%s','%s')", m_user_id.c_str(), postid.c_str(), comm);
    
    if (get_sql_result(query, false)==false)
    {
        m_url = "/html/registerErrorUserExist.html";
        return false;
    }
    m_url = "/post/" + postid;
    return true;
}